home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_xemacs.idb / usr / freeware / lib / xemacs-20.4 / lisp / packages / scroll-in-place.el.z / scroll-in-place.el
Encoding:
Text File  |  1998-05-21  |  73.1 KB  |  1,585 lines

  1.  
  2. ;;;; -*-Emacs-Lisp-*- Improved Vertical Scrolling Commands
  3. ;;;; Written by Eric Eide, last modified on 1994/11/18 21:23:01.
  4. ;;;; (C) Copyright 1993, 1994, Eric Eide and the University of Utah
  5. ;;;;
  6. ;;;; COPYRIGHT NOTICE
  7. ;;;;
  8. ;;;; This program is free software; you can redistribute it and/or modify it
  9. ;;;; under the terms of the GNU General Public License as published by the Free
  10. ;;;; Software Foundation; either version 2 of the License, or (at your option)
  11. ;;;; any later version.
  12. ;;;;
  13. ;;;; This program is distributed in the hope that it will be useful, but
  14. ;;;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  15. ;;;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. ;;;; for more details.
  17. ;;;;
  18. ;;;; You should have received a copy of the GNU General Public License along
  19. ;;;; with GNU Emacs.  If you did not, write to the Free Software Foundation,
  20. ;;;; Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21.  
  22. ;;; Synched up with: Not in FSF.
  23.  
  24. ;;;; AUTHORS
  25. ;;;;
  26. ;;;; This package was written by Eric Eide (eeide@cs.utah.edu) and was based on
  27. ;;;; a very similar package ("scroll-fix") by Joe Wells.  Almost all of the
  28. ;;;; code in this file is original, but I owe a great debt to Mr. Wells for his
  29. ;;;; ideas and his original implementation.
  30. ;;;;
  31. ;;;;   Eric Eide (eeide@cs.utah.edu)
  32. ;;;;   University of Utah
  33. ;;;;   3190 Merrill Engineering Building
  34. ;;;;   Salt Lake City, Utah  84112
  35. ;;;;
  36. ;;;;   Joe Wells (jbw@cs.bu.edu)
  37. ;;;;
  38. ;;;; Joe Wells' "scroll-fix" package is Copyright (C) 1988, 1989, and 1991 by
  39. ;;;; the Free Software Foundation.  It is distributed under the terms of the
  40. ;;;; GNU General Public License.
  41.  
  42. ;;;; LISP CODE DIRECTORY INFORMATION
  43. ;;;;
  44. ;;;; LCD Archive Entry:
  45. ;;;; scroll-in-place|Eric Eide|eeide@cs.utah.edu|
  46. ;;;; Improved vertical scrolling commands|
  47. ;;;; 1994/11/18 21:23:01|1.3|~/misc/scroll-in-place.el.Z|
  48.  
  49. ;;;; SUMMARY
  50. ;;;;
  51. ;;;; This package provides improved vertical scrolling commands for GNU Emacs.
  52. ;;;; These new commands offer the following features:
  53. ;;;;
  54. ;;;; + When a scrolling command is executed, GNU Emacs tries to keep point as
  55. ;;;;   close as possible to its original window position (window line and
  56. ;;;;   column).  This is what "scroll in place" means: point stays "in place"
  57. ;;;;   within the window.  (There are times when point must be moved from its
  58. ;;;;   original window position in order to execute the scroll; see below.)
  59. ;;;;
  60. ;;;;   The variable `scroll-in-place', which is true by default, determines
  61. ;;;;   whether or not the standard GNU Emacs scrolling commands (`scroll-down',
  62. ;;;;   `scroll-up', `scroll-other-window-down', and `scroll-other-window') use
  63. ;;;;   the "in place" features listed here.  When `scroll-in-place' is `nil'
  64. ;;;;   the standard GNU Emacs scrolling commands essentially just call the
  65. ;;;;   original versions of themselves.  (Note that even when `scroll-in-place'
  66. ;;;;   is `nil' the new versions of `scroll-down' and `scroll-up' have slightly
  67. ;;;;   different behavior when a minibuffer window is the selected window.  See
  68. ;;;;   below.)
  69. ;;;;
  70. ;;;;   It is possible to turn off (or turn on) "in place" scrolling for certain
  71. ;;;;   buffers by making buffer-local bindings of the variable `scroll-in-
  72. ;;;;   place' for those buffers.  The variable `scroll-in-place' is not usually
  73. ;;;;   buffer-local, but you can make it so if you desire.
  74. ;;;;
  75. ;;;; + Because the improved scrolling commands keep point at its original
  76. ;;;;   window position, these scrolling commands are "reversible."  The
  77. ;;;;   `scroll-up' command undoes the effect of the immediately previous
  78. ;;;;   `scroll-down' command (if any) and vice versa.  In other words, if you
  79. ;;;;   scroll up and then immediately scroll back down, the window config-
  80. ;;;;   uration is restored to its exact original state.  This allows you to
  81. ;;;;   browse through a buffer more easily, as you can always get back to the
  82. ;;;;   original configuration.
  83. ;;;;
  84. ;;;;   Note, however, that the improved scrolling commands are guaranteed to be
  85. ;;;;   reversible only if there are no intervening non-scrolling commands.
  86. ;;;;   Also, if you give a prefix argument to a scrolling command (in order to
  87. ;;;;   specify the number of lines to scroll by), previous scrolling commands
  88. ;;;;   may no longer be reversible.  More specifically, if the new prefix
  89. ;;;;   argument has a different magnitude than the previous scrolling distance,
  90. ;;;;   then any previous scrolling commands are not reversible.  The new prefix
  91. ;;;;   argument takes precedence.
  92. ;;;;
  93. ;;;;   You might find it useful to think of the scrolling commands as forming
  94. ;;;;   "chains."  A scrolling command either starts or continues a chain.  By
  95. ;;;;   issuing a non-scrolling command or by changing the number of lines to be
  96. ;;;;   scrolled, you break the chain.  (Note that simply changing the scrolling
  97. ;;;;   direction won't break the chain; changing the absolute number of lines
  98. ;;;;   to be scrolled is what breaks the chain.)  Scrolling commands are
  99. ;;;;   guaranteed to be reversible only within the current chain.  Hopefully
  100. ;;;;   that's clear enough.
  101. ;;;;
  102. ;;;; + When a scrolling command is given a prefix argument (which specifies the
  103. ;;;;   number of lines to scroll by), then that argument becomes the default
  104. ;;;;   scrolling distance for all immediately subsequent scrolling commands.
  105. ;;;;   This means that you can easily set the scrolling distance for a chain
  106. ;;;;   of scrolling commands.  Note that a new prefix argument or any non-
  107. ;;;;   scrolling command breaks the chain (as described above), and any further
  108. ;;;;   scrolling commands will use the usual defaults (or the prefix argument
  109. ;;;;   you specify at that time, of course).
  110. ;;;;
  111. ;;;;   However, there are cases in which one doesn't want the current scrolling
  112. ;;;;   command to use the default scrolling distance that was set by the
  113. ;;;;   previous scrolling command.  For example, suppose that you had special
  114. ;;;;   commands that scrolled one line up and one line down.  When you invoke
  115. ;;;;   one of these commands, the "in place" scrolling routines set the default
  116. ;;;;   scrolling distance to be just one line.  Now suppose that you use one of
  117. ;;;;   your special commands and then immediately invoke `scroll-up' (`C-v'),
  118. ;;;;   expecting it to scroll by a near windowful of text.  You would be
  119. ;;;;   disappointed --- because the previous command set the default scrolling
  120. ;;;;   distance to be just one line, `scroll-up' just scrolls by one line.
  121. ;;;;
  122. ;;;;   To solve this problem, "scroll-in-place" allows you to divide scrolling
  123. ;;;;   commands into separate "groups."  Commands in a group can only form
  124. ;;;;   chains with (and therefore, inherit defaults from) commands in the same
  125. ;;;;   group.  (Note that no command can be in more than one group.)  If you
  126. ;;;;   invoke a scrolling command that is not in the same group as that of the
  127. ;;;;   immediately previous scrolling command, then the previous chain is
  128. ;;;;   broken and you start a new chain --- with a new set of defaults.
  129. ;;;;
  130. ;;;;   So to solve the problem described above, you could put your one-line
  131. ;;;;   scrolling commands in their own group.  Once that is done, the standard
  132. ;;;;   scrolling commands will not form chains with your one-line scrolling
  133. ;;;;   commands, and therefore will not use the default scrolling distance set
  134. ;;;;   by those commands.  Problem solved!
  135. ;;;;
  136. ;;;;   By default, all "in place" scrolling commands are in a single group.  If
  137. ;;;;   you want to partition some commands into separate groups, you must do
  138. ;;;;   that yourself *before* any "in place" commands are invoked.  For more
  139. ;;;;   information about grouping commands, see the documentation for the
  140. ;;;;   variables `scroll-command-groups' and `scroll-default-command-group'.
  141. ;;;;
  142. ;;;; + The improved scrolling commands will avoid displaying empty lines past
  143. ;;;;   the end of the buffer when possible.  In other words, just as you can't
  144. ;;;;   see "dead space" before the beginning of the buffer text, the new
  145. ;;;;   scrolling commands try to avoid displaying "dead space" past the end of
  146. ;;;;   the buffer text.  This behavior is somewhat configurable; see the
  147. ;;;;   documentation for the variable `scroll-allow-blank-lines-past-eob'.
  148. ;;;;
  149. ;;;;   Dead space will be displayed if it is necessary in order to make a
  150. ;;;;   previous scrolling action reversible, however.
  151. ;;;;
  152. ;;;; + If the scrolling commands cannot keep point at its initial window
  153. ;;;;   position (because a buffer boundary is on screen and the window can't be
  154. ;;;;   scrolled as far as necessary to keep point at the right place), point is
  155. ;;;;   allowed to temporarily stray from its initial window position.  That is,
  156. ;;;;   point moves the correct number of window lines, even if it means that it
  157. ;;;;   has to stray from its desired window position.  This straying is undone
  158. ;;;;   when (and if) the scrolling action is reversed.
  159. ;;;;
  160. ;;;; + If a scrolling command tries to move point past a buffer boundary, point
  161. ;;;;   is instead moved to the boundary (the beginning or the end of the buffer
  162. ;;;;   as appropriate) and an appropriate message is displayed.  This motion is
  163. ;;;;   reversible, of course.
  164. ;;;;
  165. ;;;;   However, if point was already at the buffer boundary when the scrolling
  166. ;;;;   command was invoked, the command signals an appropriate error instead.
  167. ;;;;
  168. ;;;; + When a minibuffer window is the selected window, the new versions of
  169. ;;;;   `scroll-up' and `scroll-down' either scroll the window in the variable
  170. ;;;;   `minibuffer-scroll-window' (which is usually the window of completions)
  171. ;;;;   or the `next-window' if there is no `minibuffer-scroll-window'.  This is
  172. ;;;;   usually much more useful than scrolling the minibuffer itself.  (Note
  173. ;;;;   that this feature is available even when the variable `scroll-in-place'
  174. ;;;;   is `nil'.)
  175. ;;;;
  176. ;;;; + When a scrolling command is scrolling a window other than the selected
  177. ;;;;   window, it will signal an appropriate buffer boundary error if the
  178. ;;;;   window cannot be scrolled (because the appropriate buffer boundary is
  179. ;;;;   already visible).  This means that an error is signalled even in cases
  180. ;;;;   that would be allowed (by "straying" point or by moving it to the buffer
  181. ;;;;   boundary) if the window were selected.
  182. ;;;;
  183. ;;;;   (If an error were not signalled in these cases, then there would be many
  184. ;;;;   cases in which the last scroll in a particular direction would appear to
  185. ;;;;   do nothing because only the point position would change --- the
  186. ;;;;   displayed text would stay the same!  To avoid these cases the scrolling
  187. ;;;;   commands signal boundary errors "prematurely" when the window to be
  188. ;;;;   scrolled is not selected.)
  189. ;;;;
  190. ;;;; So how is this package different than Joe Wells' "scroll-fix" package?
  191. ;;;;
  192. ;;;; + This package provides "in place" behavior for the standard GNU Emacs
  193. ;;;;   commands by default; "scroll-fix" does not.
  194. ;;;;
  195. ;;;; + "scroll-fix" behaves differently when the window is near a buffer
  196. ;;;;   boundary.  Instead of allowing point to stray, "scroll-fix" first does
  197. ;;;;   an incomplete scroll (i.e., moves point less than the full distance in
  198. ;;;;   order to keep point at the desired window position) and then pops point
  199. ;;;;   to the buffer boundary.  I think that the behavior of this package is
  200. ;;;;   somewhat move intuitive, especially for small scrolling distances.
  201. ;;;;
  202. ;;;; + The scrolling commands in this package will appropriately signal buffer
  203. ;;;;   boundary errors; the commands in "scroll-fix" never signal boundary
  204. ;;;;   errors.  This makes it difficult to allow "scroll-fix" to replace the
  205. ;;;;   standard `scroll-down' and `scroll-up' commands because some other
  206. ;;;;   packages (e.g., VM and GNUS) expect the scrolling commands to signal
  207. ;;;;   these errors as necessary.
  208. ;;;;
  209. ;;;; + This package handles long lines correctly.  (But see PROBLEMS, below.)
  210. ;;;;
  211. ;;;; + "scroll-fix" handles prefix arguments differently.  In "scroll-fix", a
  212. ;;;;   number-containing prefix argument always breaks any running chain of
  213. ;;;;   scrolling commands.  The prefix argument `-' (the symbol minus,
  214. ;;;;   generated by `C-u -') causes a temporary change in direction --- a
  215. ;;;;   change for only the current command.  In this package, however, a
  216. ;;;;   number-containing prefix argument only breaks a running chain if it has
  217. ;;;;   a different magnitude than the default scrolling distance, and the
  218. ;;;;   prefix argument `-' causes a permanent change in the sign of the default
  219. ;;;;   scrolling distance --- a change visible to immediately subsequent
  220. ;;;;   scrolling commands.
  221. ;;;;
  222. ;;;; + This package keeps track of the set of "in place" scrolling commands
  223. ;;;;   dynamically, in order to detect "chains" of scrolling commands.
  224. ;;;;   "scroll-fix" has a fixed list of scrolling commands, so "scroll-fix"
  225. ;;;;   cannot keep track of some chains.  (Again, "scroll-fix" interacts badly
  226. ;;;;   with VM and GNUS.)  And because "scroll-fix" keeps a static list of
  227. ;;;;   scrolling commands, it is a bad idea to call its "in place" commands
  228. ;;;;   from a program.  This package, because it maintains the information
  229. ;;;;   dynamically, has no such problems.
  230. ;;;;
  231. ;;;; + This package allows one to divide the "in place" scrolling commands into
  232. ;;;;   groups; a command in a group only forms chains with the members of its
  233. ;;;;   group.  "scroll-fix" has no notion of command groups.
  234. ;;;;
  235. ;;;; + This package provides "in place" versions of the standard GNU Emacs
  236. ;;;;   commands `scroll-other-window-down' and `scroll-other-window'.
  237. ;;;;
  238. ;;;; + This package will refuse to scroll non-selected windows (by signalling
  239. ;;;;   an error) when the displayed text would not change, as described in the
  240. ;;;;   feature list above.
  241. ;;;;
  242. ;;;; + When a minibuffer window is selected, this package always scrolls a
  243. ;;;;   window other than the minibuffer.  "scroll-fix" will scroll another
  244. ;;;;   window only if the entire minibuffer contents are visible.
  245. ;;;;
  246. ;;;; + "scroll-fix" provides a command to toggle the "in place" behavior of the
  247. ;;;;   standard GNU Emacs commands.  This package doesn't; you'll have to set
  248. ;;;;   the option manually with the command `set-variable'.
  249. ;;;;
  250. ;;;; + This package has gratuitous variable renaming (insert smile here!):
  251. ;;;;
  252. ;;;;   "scroll-fix" user variable            Equivalent in this package
  253. ;;;;   -----------------------------------------------------------------------
  254. ;;;;   scroll-in-place                       (none)
  255. ;;;;   scroll-in-place-replace-original      scroll-in-place
  256. ;;;;   scroll-in-place-eob-blank-allowed     scroll-allow-blank-lines-past-eob
  257. ;;;;
  258. ;;;; + This package allows programmers to specify the default scrolling
  259. ;;;;   distance (i.e., the default distance used when starting a new chain of
  260. ;;;;   scrolling commands) for custom scrolling commands.
  261.  
  262. ;;;; COMMANDS AND FUNCTIONS
  263. ;;;;
  264. ;;;; This package provides the following "in place" versions of GNU Emacs'
  265. ;;;; standard vertical scrolling commands:
  266. ;;;;
  267. ;;;;   scroll-down-in-place
  268. ;;;;   scroll-up-in-place
  269. ;;;;   scroll-other-window-down-in-place
  270. ;;;;   scroll-other-window-in-place
  271. ;;;;
  272. ;;;; The variable `scroll-in-place', which is true by default, determines
  273. ;;;; whether or not the new versions of the standard GNU Emacs scrolling
  274. ;;;; commands (`scroll-down', `scroll-up', `scroll-other-window-down', and
  275. ;;;; `scroll-other-window') use the "in place" features listed above.  When
  276. ;;;; `scroll-in-place' is `nil' the standard GNU Emacs scrolling commands
  277. ;;;; essentially just call the original versions of themselves.  (Note that
  278. ;;;; even when `scroll-in-place' is `nil' the new versions of `scroll-down' and
  279. ;;;; `scroll-up' have slightly different behavior when a minibuffer window is
  280. ;;;; the selected window.  See the feature list above.)
  281. ;;;;
  282. ;;;; NOTE that this package redefines the standard GNU Emacs commands `scroll-
  283. ;;;; down', `scroll-up', `scroll-other-window-down', and `scroll-other-window'
  284. ;;;; (in order to check the variable `scroll-in-place', as described above).
  285. ;;;; The command `scroll-other-window-down' first appeared as a standard
  286. ;;;; command in the FSF's GNU Emacs 19.26.
  287. ;;;;
  288. ;;;; This package also provides the following functions and variables which are
  289. ;;;; of use to programmers:
  290. ;;;;
  291. ;;;;   scroll-window
  292. ;;;;   scroll-window-in-place
  293. ;;;;   scroll-window-in-place-continue-sequence
  294. ;;;;   scroll-default-lines (variable)
  295. ;;;;   scroll-command-groups (variable)
  296. ;;;;
  297. ;;;; The `scroll-window-in-place' function is the heart of the "in place"
  298. ;;;; scrolling commands.  `scroll-window' is a function that checks the
  299. ;;;; variable `scroll-in-place' and calls the appropriate scrolling function
  300. ;;;; (either `scroll-window-in-place' or one of the original versions of
  301. ;;;; `scroll-down' and `scroll-up').  The function `scroll-window-in-place-
  302. ;;;; continue-sequence' is provided in order to preserve running "chains" of
  303. ;;;; scrolling commands as described above.
  304. ;;;;
  305. ;;;; The variable `scroll-default-lines' determines the default scrolling
  306. ;;;; distance when a new chain of "in place" scrolling commands begins.  If
  307. ;;;; this variable is not a number, then the default distance is the height of
  308. ;;;; the window to be scrolled minus `next-screen-context-lines'.  The variable
  309. ;;;; `scroll-command-groups' contains the explicit groups of "in place"
  310. ;;;; scrolling commands; for more information read the variable documentation.
  311.  
  312. ;;;; YOUR .EMACS FILE
  313. ;;;;
  314. ;;;; To use this package, you simply need to load it from within your ".emacs"
  315. ;;;; file:
  316. ;;;;
  317. ;;;;   (require 'scroll-in-place)
  318. ;;;;
  319. ;;;; By default, this package provides for the standard GNU Emacs vertical
  320. ;;;; scrolling commands (`scroll-down', `scroll-up', `scroll-other-window-
  321. ;;;; down', and `scroll-other-window') to use the "in place" features.  If you
  322. ;;;; would rather not have this, set the variable `scroll-in-place' to `nil':
  323. ;;;;
  324. ;;;;   (setq scroll-in-place nil)
  325. ;;;;
  326. ;;;; When `scroll-in-place' is `nil' you will have to bind keys in order to
  327. ;;;; call the "in place" scrolling commands.  For example, you might want to do
  328. ;;;; the following:
  329. ;;;;
  330. ;;;;   (global-set-key "\M-v" 'scroll-down-in-place)
  331. ;;;;   (global-set-key "\C-v" 'scroll-up-in-place)
  332. ;;;;
  333. ;;;; Sun users should also read the PROBLEMS section, below.
  334. ;;;;
  335. ;;;; ADVANCED CUSTOMIZATION
  336. ;;;;
  337. ;;;; If you want to partition certain "in place" scrolling commands into
  338. ;;;; separate groups, you should do something like the following:
  339. ;;;;
  340. ;;;;   ;; Make one group containing the commands `scroll-down-one-line' and
  341. ;;;;   ;; `scroll-up-one-line'.  (These are not standard GNU Emacs commands.)
  342. ;;;;   (setq scroll-command-groups
  343. ;;;;         (list '(scroll-down-one-line scroll-up-one-line)))
  344. ;;;;
  345. ;;;; You could write the `scroll-down-one-line' command like this:
  346. ;;;;
  347. ;;;;   (defun scroll-down-one-line (arg)
  348. ;;;;     "Scroll down one line, or number of lines specified by prefix arg."
  349. ;;;;     (interactive "P")
  350. ;;;;     (let ((scroll-default-lines 1))
  351. ;;;;       (scroll-down-in-place arg)))
  352. ;;;;
  353. ;;;; If you want to disable "in place" scrolling for windows that display a
  354. ;;;; particular buffer (while leaving it available in other windows), you can
  355. ;;;; make `scroll-in-place' a buffer-local variable for that buffer and then
  356. ;;;; bind that local copy of `scroll-in-place' to `nil'.  This is the kind of
  357. ;;;; thing that one generally does in a major mode hook.  For example, you can
  358. ;;;; disable "in place" scrolling of GNUS article windows with the following
  359. ;;;; code:
  360. ;;;;
  361. ;;;;   (setq gnus-article-mode-hook
  362. ;;;;         (function (lambda ()
  363. ;;;;                     (make-local-variable 'scroll-in-place)
  364. ;;;;                     (setq scroll-in-place nil))))
  365. ;;;;   ;; Set the variable `gnus-Article-mode-hook' instead if you are using
  366. ;;;;   ;; an old version of GNUS, say version 3.13 or 3.14.
  367. ;;;;
  368. ;;;; The variable `scroll-allow-blank-lines-past-eob' can also be made local to
  369. ;;;; particular buffers, if you desire.  (But why would you want to do that?)
  370.  
  371. ;;;; PROBLEMS
  372. ;;;;
  373. ;;;; + It is sometimes difficult for one's eyes to follow an incomplete scroll
  374. ;;;;   (i.e., a scroll in which the text doesn't move as far as one expected),
  375. ;;;;   especially when the scrolled window is not selected (and therefore that
  376. ;;;;   window's point is not highlighted).  One can lose one's place in the
  377. ;;;;   text.
  378. ;;;;
  379. ;;;; + The names `scroll-down-in-place' and `scroll-up-in-place' conflict with
  380. ;;;;   two commands in the GNU Emacs terminal-specific file "term/sun.el".
  381. ;;;;   This means that in order to load this package correctly, Sunterm users
  382. ;;;;   will have to use the hook `term-setup-hook'.  For example, you might put
  383. ;;;;   the following form in your ".emacs" file:
  384. ;;;;
  385. ;;;;   (setq term-setup-hook (function (lambda () (require 'scroll-in-place))))
  386. ;;;;
  387. ;;;;   If this is confusing, get help from your local GNU Emacs guru.
  388. ;;;;
  389. ;;;; + `scroll-determine-goal-column' tries to honor the variable `track-eol'
  390. ;;;;   if it is set.  But when lines are being wrapped we can't move point past
  391. ;;;;   the wrap --- or else it is possible that scrolling won't work correctly.
  392. ;;;;   In short, this package honors `track-eol' as best it can.
  393. ;;;;
  394. ;;;; + `scroll-window-in-place' can become confused when something changes the
  395. ;;;;   window "out from under it."  By "confused" I mean that it is possible
  396. ;;;;   for `scroll-window-in-place' to think that it should continue the
  397. ;;;;   running sequence of "in place" scrolls when it should really probably
  398. ;;;;   start a new sequence.  For example, if a process filter inserts text
  399. ;;;;   into the buffer and moves point, `scroll-window-in-place' loses track of
  400. ;;;;   where point should be and where the window should start.  Commands that
  401. ;;;;   call a "scroll in place" function and then subsequently move point can
  402. ;;;;   also confuse `scroll-window-in-place'.
  403. ;;;;
  404. ;;;;   To correct some of this confusion, `scroll-window-in-place' could keep
  405. ;;;;   track of the final positions of `window-start' and `window-point',
  406. ;;;;   possibly with both markers and character positions.  In my experience
  407. ;;;;   the "in place" scrolling commands are almost never confused (except by
  408. ;;;;   fancy packages that do their own fancy kinds of scrolling, as described
  409. ;;;;   below), so the extra sanity checking isn't worth the effort.  If your
  410. ;;;;   mileage varies let me know.
  411. ;;;;
  412. ;;;; + The "in place" scrolling commands can interact poorly with packages that
  413. ;;;;   provide their own special scrolling commands.  For example, there are
  414. ;;;;   varying degrees of conflict with Rmail, VM, and GNUS.
  415. ;;;;
  416. ;;;;   RMAIL
  417. ;;;;
  418. ;;;;   In the version of Rmail that is part of the FSF's GNU Emacs 19 (19.25
  419. ;;;;   through 19.28 at least), the command `rmail-summary-scroll-msg-down' in
  420. ;;;;   the file "rmailsum.el" fails to work properly when "in place" scrolling
  421. ;;;;   is enabled for the Rmail message buffer.  (The source of the conflict:
  422. ;;;;   the "in place" scrolling commands and Emacs' standard scrolling commands
  423. ;;;;   interpret the argument '- in different ways.)  Fortunately it is easy to
  424. ;;;;   patch Rmail.  Send me mail if you would like to receive a copy of these
  425. ;;;;   patches.
  426. ;;;;
  427. ;;;;   I know of no conflicts between the "in place" scrolling commands and
  428. ;;;;   older versions of Rmail (i.e., versions that came with GNU Emacs 18).
  429. ;;;;
  430. ;;;;   VM
  431. ;;;;
  432. ;;;;   `scroll-window-in-place' is *very* confused by VM 5's message scrolling
  433. ;;;;   commands, especially because VM 5 rebuilds Emacs' window configuration
  434. ;;;;   from scratch so often.  I have written an experimental set of patches
  435. ;;;;   for VM 5.70 that allows VM 5 to use the "scroll-in-place" features; send
  436. ;;;;   me mail if you would like to receive a copy of these patches.  I hope
  437. ;;;;   that someday my patches will be incorporated into VM.
  438. ;;;;
  439. ;;;;   `scroll-window-in-place' is not confused by VM 4.41's message scrolling
  440. ;;;;   commands, however.
  441. ;;;;
  442. ;;;;   GNUS
  443. ;;;;
  444. ;;;;   `scroll-window-in-place' can be *slightly* confused by GNUS' article
  445. ;;;;   scrolling commands because they move point to the last line of the
  446. ;;;;   article window and then scroll the text.  (This is the case for at least
  447. ;;;;   GNUS versions 3.13 through 4.1, inclusive.)  The potential conflict is
  448. ;;;;   so minor, however, that you'll probably never notice it.  I never do.
  449. ;;;;
  450. ;;;;   A severe conflict, however, exists between the "in place" scrolling
  451. ;;;;   commands and the add-on "gnus-hide" package.  "gnus-hide" can elide
  452. ;;;;   signatures at the ends of articles but it does so in a way that causes
  453. ;;;;   `scroll-window-in-place', as invoked by the GNUS scrolling commands, not
  454. ;;;;   to signal end-of-buffer conditions at the right times.  Someday I may
  455. ;;;;   write new article scrolling commands for GNUS.
  456. ;;;;
  457. ;;;; + Process filters that call scrolling functions can cause confusion.  They
  458. ;;;;   may break running chains of "in place" scrolling commands and they may
  459. ;;;;   set up inappropriate defaults for future scrolling commands.  Maybe this
  460. ;;;;   is a moot problem, as I am currently unaware of any process filters that
  461. ;;;;   invoke scrolling commands (although many filters move point around,
  462. ;;;;   which will also confuse `scroll-window-in-place').
  463.  
  464. ;; sb -- Added turn-on and turn-off hook functions to prepare for making this
  465. ;;  a standardly dumped package with XEmacs.
  466.  
  467. ;; (provide 'scroll-in-place) at the end of this file.
  468.  
  469.  
  470. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  471. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  472. ;;;;
  473. ;;;; Here are the variable declarations, both user options and internal
  474. ;;;; variables.
  475. ;;;;
  476. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  477. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  478.  
  479. (defvar scroll-in-place t
  480.   "*When this variable is true (i.e., non-`nil'), the standard GNU Emacs
  481. vertical scrolling commands `scroll-down', `scroll-up', `scroll-other-window-
  482. down', and `scroll-other-window' will attempt to keep point at its current
  483. position in the window (window line and column).  In other words, point stays
  484. \"in place\" within the window.
  485.  
  486. When this variable is `nil' the standard GNU Emacs vertical scrolling commands
  487. behave as usual.  The \"in place\" equivalents, however, are still available as
  488. separate commands.
  489.  
  490. This variable may be made buffer-local in order to disable (or enable) \"in
  491. place\" scrolling in particular buffers."
  492.   ;; I have thought about dividing `scroll-in-place' into three variables: a
  493.   ;; list of commands that always scroll in place, a list of commands that
  494.   ;; never scroll in place, and a flag that determines the default behavior of
  495.   ;; other scrolling commands.  This could make it easier to make "in place"
  496.   ;; scrolling the default because one could single out certain ill-behaved
  497.   ;; commands.  But as of now I'm sure that the added complexity would really
  498.   ;; be worth it.
  499.   )
  500.  
  501. (defvar scroll-allow-blank-lines-past-eob nil
  502.   "*When this variable is `nil' the \"in place\" scrolling commands will avoid
  503. displaying empty lines past the end of the buffer text.  In other words, just
  504. as you can't see \"dead space\" before the beginning of the buffer text, the
  505. \"in place\" scrolling commands try to avoid displaying \"dead space\" past the
  506. end of the buffer text.  This helps make the most of window real estate.
  507.  
  508. Note that sometimes it is necessary to display \"dead space\" in order to make
  509. a previous scrolling action reversible.
  510.  
  511. When this variable is non-`nil' the \"in place\" scrolling commands will always
  512. allow blank lines to be shown past the end of the buffer.")
  513.  
  514. ;;;;
  515. ;;;; The following variables are not user options, but are intended to be set
  516. ;;;; by code outside this package.
  517. ;;;;
  518.  
  519. (defvar scroll-default-lines nil
  520.   "The default number of lines to be scrolled by when a new sequence of \"in
  521. place\" scrolling commands begins.  Of course, when an explicit number of lines
  522. is specified, that explicit number takes precedence.  See the documentation for
  523. the function `scroll-window-in-place' for more information.
  524.  
  525. If this variable is not bound to a number, then the default number of lines is
  526. the height of the window to be scrolled minus `next-screen-context-lines'.
  527.  
  528. This variable should not be set globally!  Commands that want to specify a
  529. default scrolling distance should just bind the variable `scroll-default-lines'
  530. temporarily.")
  531.  
  532. (defvar scroll-command-groups nil
  533.   "The explicitly specified \"groups\" of \"in place\" scrolling commands.
  534. This variable should be set before or immediately after the \"in place\"
  535. scrolling package is loaded, and then not changed after that.
  536.  
  537. Usually, \"in place\" scrolling commands share state (e.g., the number of lines
  538. to scroll by) with any and all immediately previous \"in place\" scrolling
  539. commands.  Sometimes, however, this is undesirable.  In these cases the \"in
  540. place\" scrolling commands can be divided into groups.  A command in a group
  541. only shares state with members of its group.
  542.  
  543. Each element of `scroll-command-groups' is a list that contains all of the
  544. members of a unique command group.  For example, if there were only one
  545. explicit group and that group contained the commands `scroll-down-one-line' and
  546. `scroll-up-one-line', then `scroll-command-groups' would be set to:
  547.  
  548.   ((scroll-down-one-line scroll-up-one-line))
  549.  
  550. Commands that are not in any explicitly specified group are added to a default
  551. group.  That group is stored in the variable `scroll-default-command-group'.
  552.  
  553. The \"in place\" scrolling functions assume that all of the scrolling command
  554. groups are nonintersecting (i.e., no command is in more than one group) and
  555. only contain \"in place\" scrolling commands.")
  556.  
  557. ;;;;
  558. ;;;; The variables below this point are internal to this package.
  559. ;;;;
  560.  
  561. (defvar scroll-default-command-group nil
  562.   "The set of \"in place\" scrolling commands that are not members of any
  563. explicitly defined group of commands.  This set of commands is an implicitly
  564. defined group, constructed as \"in place\" commands are invoked, and members of
  565. this group share state among themselves.  See the documentation for the
  566. variable `scroll-command-groups' for more information.")
  567.  
  568. (defvar scroll-initially-displayed-lines 0
  569.   "The number of window lines that contained buffer text when the current
  570. sequence of \"in place\" scrolling commands started.  Unless the variable
  571. `scroll-in-place-allow-blank-lines-past-eob' is true, the \"in place\"
  572. scrolling commands ensure that at least this many text lines are visible at all
  573. times.")
  574.  
  575. (defvar scroll-previous-window nil
  576.   "The window that was most recently scrolled by an \"in place\" scrolling
  577. command.")
  578.  
  579. (defvar scroll-previous-lines 0
  580.   "The number of window lines that the previous \"in place\" scrolling command
  581. attempted to scroll.")
  582.  
  583. (defvar scroll-goal-column 0
  584.   "The desired horizontal window position for point, used by the \"in place\"
  585. scrolling commands.")
  586.  
  587. (defvar scroll-boundary-previous-point nil
  588.   "The value of point before point was moved to a buffer boundary.")
  589.  
  590. (defvar scroll-boundary-previous-lines 0
  591.   "The number of lines that point moved when it moved to a buffer boundary.")
  592.  
  593. (defvar scroll-boundary-error-command nil
  594.   "The value of `this-command' when an \"in place\" scrolling command signalled
  595. a buffer boundary error.  This is used to decide how subsequent scrolling
  596. commands should recover from the error.")
  597.  
  598. (defvar scroll-boundary-error-point nil
  599.   "The value of point when an \"in place\" scrolling command signalled a buffer
  600. boundary error.  This is used to decide how subsequent scrolling commands
  601. should recover from the error."
  602.   ;; This variable is used as a flag, indicating whether or not the previous
  603.   ;; "in place" scrolling command signalled an error.
  604.   )
  605.  
  606. (defvar scroll-window-debt 0
  607.   "The difference between the number of lines an \"in place\" scrolling command
  608. tried to scroll a window and the number of lines that the window actually
  609. scrolled.  This difference is the \"debt\" in the window's starting position.
  610. Subsequent \"in place\" scrolling commands try to make up this debt.")
  611.  
  612. (defconst scroll-pos-visible-bug-p
  613.   ;; On September 14, 1993, David Hughes <djh@Harston.CV.COM> told me that
  614.   ;; Lucid GNU Emacs 19.8 had inherited the bug from Epoch... sigh.
  615.   (let ((old-match-data (match-data)))
  616.     (unwind-protect
  617.     (or (and (boundp 'epoch::version)
  618.          (if (string-match "\\`4\\." emacs-version) t nil)
  619.          )
  620.         (and (string-match "Lucid" emacs-version)
  621.          (if (string-match "\\`19\\.8\\." emacs-version) t nil)
  622.          )
  623.         )
  624.       (store-match-data old-match-data)))
  625.   "A flag, set when this version of GNU Emacs has a buggy version of the
  626. function `pos-visible-in-window-p' that returns `nil' when given `(point-max)'
  627. and `(point-max)' is on the last line of the window.  Currently, this flag is
  628. set for all versions of Epoch 4 and for Lucid GNU Emacs 19.8.")
  629.  
  630.  
  631. ;; Hook functions to make turning the mode on and off easier.
  632. (defun turn-on-scroll-in-place ()
  633.   "Unconditionally turn on scroll-in-place mode."
  634.   (set (make-local-variable 'scroll-in-place) t))
  635.  
  636. (defun turn-off-scroll-in-place ()
  637.   "Unconditionally turn on scroll-in-place mode."
  638.   (set (make-local-variable 'scroll-in-place) nil))
  639.  
  640.  
  641. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  642. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  643. ;;;;
  644. ;;;; Here are the window-choosing auxiliary functions used by the new scrolling
  645. ;;;; commands.
  646. ;;;;
  647. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  648. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  649.  
  650. (defun scroll-choose-window ()
  651.   "Choose the window to be scrolled by the commands `scroll-down', `scroll-up',
  652. `scroll-down-in-place', and `scroll-up-in-place'.
  653.  
  654. The rules are simple.  If the selected window is not a minibuffer window, then
  655. just choose the selected window.
  656.  
  657. However, when a minibuffer window is selected, look first for the `minibuffer-
  658. scroll-window'.  The `minibuffer-scroll-window' is usually the window that
  659. displays completions.  If it exists, choose it; otherwise choose the next
  660. window after the selected window in the canonical ordering of windows.  The
  661. next window is generally the one below the selected window, or the one at the
  662. top of the screen if the selected window is at the bottom of the screen."
  663.   (let ((selected-window (selected-window)))
  664.     (if (window-minibuffer-p selected-window)
  665.     ;; A minibuffer window is selected --- scroll some other window.
  666.     (if (window-live-p minibuffer-scroll-window)
  667.         minibuffer-scroll-window
  668.       ;; We know that the (selected) minibuffer is active, so `next-window'
  669.       ;; will examine all of the frames that share this minibuffer.
  670.       ;; Should we consider `other-window-scroll-buffer' here?  I don't
  671.       ;; believe so.
  672.       (next-window selected-window))
  673.       selected-window)))
  674.  
  675. ;;;
  676. ;;;
  677. ;;;
  678.  
  679. (defun scroll-choose-other-window ()
  680.   "Choose the window to be scrolled by the commands `scroll-other-window-down',
  681. `scroll-other-window', `scroll-other-window-down-in-place', and `scroll-other-
  682. window-in-place'.
  683.  
  684. The rules are these.  If the selected window is not a minibuffer window, then
  685. choose either:
  686.  
  687.   + a window that displays the `other-window-scroll-buffer', if that buffer
  688.     exists.  Note, this function will display that buffer if necessary.
  689.  
  690.   + the next window after the selected window in the canonical ordering of
  691.     windows.  The next window is generally the one below the selected window,
  692.     or the one at the top of the screen if the selected window is at the bottom
  693.     of the screen.
  694.  
  695. However, when a minibuffer window is selected, look first for the `minibuffer-
  696. scroll-window'.  The `minibuffer-scroll-window' is usually the window that
  697. displays completions.  If it exists, choose it; otherwise choose the window to
  698. be scrolled as described above (`other-window-scroll-buffer' or next window).
  699.  
  700. This function is essentially a Lisp version of the function `other-window-for-
  701. scrolling' which first appeared in the FSF's GNU Emacs 19.26."
  702.   (let* ((no-error nil)
  703.      (selected-window (selected-window))
  704.      (other-window nil))
  705.     (setq other-window
  706.       (cond ((and (window-minibuffer-p selected-window)
  707.               (window-live-p minibuffer-scroll-window))
  708.          ;; Don't signal an error when `minibuffer-scroll-window' is
  709.          ;; the minibuffer itself --- which would be really weird, but
  710.          ;; isn't necessarily erroneous.
  711.          (setq no-error t)
  712.          minibuffer-scroll-window)
  713.         
  714.         ((and ;; `other-window-scroll-buffer' is an Emacs 19 invention.
  715.               (boundp 'other-window-scroll-buffer)
  716.               (bufferp other-window-scroll-buffer)
  717.               ;; `buffer-name' is `nil' if the buffer has been killed.
  718.               (buffer-name other-window-scroll-buffer))
  719.          ;; This is what FSF GNU Emacs 19.26 does, but it occurred to
  720.          ;; me: what if one of these forms returns the selected window?
  721.          ;; Signalling an error would be bad news, so I added a flag.
  722.          (setq no-error t)
  723.          (or (get-buffer-window other-window-scroll-buffer)
  724.              (display-buffer other-window-scroll-buffer t)))
  725.         
  726.         ((let ((next-window (next-window selected-window)))
  727.            (if (eq next-window selected-window)
  728.                nil
  729.              next-window)))
  730.         
  731.         (t
  732.          ;; In Emacs 19 (FSF, Lucid, and XEmacs), look for a window on
  733.          ;; another visible frame.  This could be written for
  734.          ;; Epoch, too, I suppose...
  735.          (condition-case nil
  736.              (let ((this-window (next-window selected-window nil t)))
  737.                (while (not (or (eq this-window selected-window)
  738.                        (scroll-choose-window-frame-visible-p
  739.                     this-window)))
  740.              (setq this-window (next-window this-window nil t)))
  741.                this-window)
  742.            ;; In older versions of Emacs, `next-window' didn't accept
  743.            ;; three arguments.  Catch this error and then return the
  744.            ;; selected window --- which will cause another error to be
  745.            ;; signalled later on.
  746.            (wrong-number-of-arguments selected-window))
  747.          )
  748.         ))
  749.     
  750.     (if (and (not no-error)
  751.          (eq selected-window other-window))
  752.     (error "There is no other window."))
  753.     other-window))
  754.  
  755. ;;;
  756. ;;;
  757. ;;;
  758.  
  759. (defun scroll-choose-window-frame-visible-p (window)
  760.   "Return a true value if the frame of the given WINDOW is visible."
  761.   (cond ((fboundp 'window-frame)
  762.      (eq t (frame-visible-p (window-frame window))))
  763.     (t t)))
  764.  
  765.  
  766. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  767. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  768. ;;;;
  769. ;;;; Here are the "in place" scrolling commands (interactive functions) and the
  770. ;;;; replacements for the standard GNU Emacs vertical scrolling commands.
  771. ;;;;
  772. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  773. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  774.  
  775. ;;;;
  776. ;;;; Here are the new scroll "in place" commands.
  777. ;;;;
  778.  
  779. (defun scroll-down-in-place (&optional lines)
  780.   "Scroll the text of the current window downward by LINES lines, leaving point
  781. as close as possible to its current window position (window line and column).
  782. In other words, point is left \"in place\" within the window.  As a special
  783. case, when the current window is a minibuffer window, this command scrolls the
  784. `minibuffer-scroll-window' (which is usually the list of completions) if it
  785. exists, or otherwise the next window in the canonical ordering of windows.
  786.  
  787. If the optional argument LINES is `nil', scroll the window by the same amount
  788. it was moved by the immediately previous \"in place\" scrolling command, or by
  789. the value of the variable `scroll-default-lines' (usually almost a windowful)
  790. if the previous command was not an \"in place\" scrolling command (or when that
  791. previous command scrolled some other window, or when other circumstances
  792. prevent the previous scrolling distance from being used).  If LINES is the
  793. symbol `-', then the scrolling distance is determined as if LINES had been
  794. `nil' and then that distance is multiplied by -1.
  795.  
  796. If the window cannot be scrolled by the full distance, point is allowed to
  797. stray from its initial position so that it can move the full number of lines.
  798. If point cannot move the full number of lines, point is moved to the buffer
  799. boundary.  Any immediately subsequent \"in place\" scrolling commands will try
  800. to restore point to its initial window position."
  801.   (interactive "P")
  802.   (scroll-window-in-place (scroll-choose-window) lines -1))
  803.  
  804. ;;;
  805. ;;;
  806. ;;;
  807.  
  808. (defun scroll-up-in-place (&optional lines)
  809.   "Scroll the text of the current window upward by LINES lines, leaving point
  810. as close as possible to its current window position (window line and column).
  811. In other words, point is left \"in place\" within the window.  As a special
  812. case, when the current window is a minibuffer window, this command scrolls the
  813. `minibuffer-scroll-window' (which is usually the list of completions) if it
  814. exists, or otherwise the next window in the canonical ordering of windows.
  815.  
  816. If the optional argument LINES is `nil', scroll the window by the same amount
  817. it was moved by the immediately previous \"in place\" scrolling command, or by
  818. the value of the variable `scroll-default-lines' (usually almost a windowful)
  819. if the previous command was not an \"in place\" scrolling command (or when that
  820. previous command scrolled some other window, or when other circumstances
  821. prevent the previous scrolling distance from being used).  If LINES is the
  822. symbol `-', then the scrolling distance is determined as if LINES had been
  823. `nil' and then that distance is multiplied by -1.
  824.  
  825. If the window cannot be scrolled by the full distance, point is allowed to
  826. stray from its initial position so that it can move the full number of lines.
  827. If point cannot move the full number of lines, point is moved to the buffer
  828. boundary.  Any immediately subsequent \"in place\" scrolling commands will try
  829. to restore point to its initial window position."
  830.   (interactive "P")
  831.   (scroll-window-in-place (scroll-choose-window) lines 1))
  832.  
  833. ;;;
  834. ;;; The command `scroll-other-window-down' first appeared in FSF GNU Emacs
  835. ;;; 19.26.
  836. ;;;
  837.  
  838. (defun scroll-other-window-down-in-place (&optional lines)
  839.   "Scroll the text of the next window downward by LINES lines, leaving point in
  840. that window as close as possible to its current window position (window line
  841. and column).  In other words, point is left \"in place\" within the window.
  842. The next window is generally the one below the current one, or the one at the
  843. top of the screen if the current window is at the bottom of the screen.  In
  844. special circumstances this command will scroll a window other than the next
  845. window.  Read the documentation for the function `scroll-choose-other-window'
  846. for details.
  847.  
  848. If the optional argument LINES is `nil', scroll the window by the same amount
  849. it was moved by the immediately previous \"in place\" scrolling command, or by
  850. the value of the variable `scroll-default-lines' (usually almost a windowful)
  851. if the previous command was not an \"in place\" scrolling command (or when that
  852. previous command scrolled some other window, or when other circumstances
  853. prevent the previous scrolling distance from being used).  If LINES is the
  854. symbol `-', then the scrolling distance is determined as if LINES had been
  855. `nil' and then that distance is multiplied by -1.
  856.  
  857. If the window cannot be scrolled by the full distance, point is allowed to
  858. stray from its initial position so that it can move the full number of lines.
  859. If point cannot move the full number of lines, point is moved to the buffer
  860. boundary.  Any immediately subsequent \"in place\" scrolling commands will try
  861. to restore point to its initial window position.
  862.  
  863. If it is impossible to scroll the text of the window at all (because a buffer
  864. boundary is already visible), this command signals a buffer boundary error.
  865. The error is signalled even if point could otherwise move the full number of
  866. lines."
  867.   (interactive "P")
  868.   (scroll-window-in-place (scroll-choose-other-window) lines -1))
  869.  
  870. ;;;
  871. ;;;
  872. ;;;
  873.  
  874. (defun scroll-other-window-in-place (&optional lines)
  875.   "Scroll the text of the next window upward by LINES lines, leaving point in
  876. that window as close as possible to its current window position (window line
  877. and column).  In other words, point is left \"in place\" within the window.
  878. The next window is generally the one below the current one, or the one at the
  879. top of the screen if the current window is at the bottom of the screen.  In
  880. special circumstances this command will scroll a window other than the next
  881. window.  Read the documentation for the function `scroll-choose-other-window'
  882. for details.
  883.  
  884. If the optional argument LINES is `nil', scroll the window by the same amount
  885. it was moved by the immediately previous \"in place\" scrolling command, or by
  886. the value of the variable `scroll-default-lines' (usually almost a windowful)
  887. if the previous command was not an \"in place\" scrolling command (or when that
  888. previous command scrolled some other window, or when other circumstances
  889. prevent the previous scrolling distance from being used).  If LINES is the
  890. symbol `-', then the scrolling distance is determined as if LINES had been
  891. `nil' and then that distance is multiplied by -1.
  892.  
  893. If the window cannot be scrolled by the full distance, point is allowed to
  894. stray from its initial position so that it can move the full number of lines.
  895. If point cannot move the full number of lines, point is moved to the buffer
  896. boundary.  Any immediately subsequent \"in place\" scrolling commands will try
  897. to restore point to its initial window position.
  898.  
  899. If it is impossible to scroll the text of the window at all (because a buffer
  900. boundary is already visible), this command signals a buffer boundary error.
  901. The error is signalled even if point could otherwise move the full number of
  902. lines."
  903.   (interactive "P")
  904.   (scroll-window-in-place (scroll-choose-other-window) lines 1))
  905.  
  906. ;;;;
  907. ;;;; Here are the replacements for GNU Emacs' standard vertical scrolling
  908. ;;;; commands.
  909. ;;;;
  910.  
  911. (or (fboundp 'original-scroll-down)
  912.     (fset 'original-scroll-down (symbol-function 'scroll-down)))
  913. (or (fboundp 'original-scroll-up)
  914.     (fset 'original-scroll-up (symbol-function 'scroll-up)))
  915. (or (fboundp 'original-scroll-other-window-down)
  916.     ;; `scroll-other-window-down' first appeared in FSF GNU Emacs 19.26.
  917.     (if (fboundp 'scroll-other-window-down)
  918.     (fset 'original-scroll-other-window-down
  919.           (symbol-function 'scroll-other-window-down))
  920.       ))
  921. (or (fboundp 'original-scroll-other-window)
  922.     (fset 'original-scroll-other-window (symbol-function 'scroll-other-window))
  923.     )
  924.  
  925. ;;;
  926. ;;;
  927. ;;;
  928.  
  929. (defun scroll-down (&optional lines)
  930.   "Scroll the text of the current window downward by LINES lines.  As a special
  931. case, when the current window is a minibuffer window, this command scrolls the
  932. `minibuffer-scroll-window' (which is usually the list of completions) if it
  933. exists, or otherwise the next window in the canonical ordering of windows.
  934.  
  935. The argument LINES is optional.  Its meaning depends on the current value of
  936. the variable `scroll-in-place'.
  937.  
  938. When the variable `scroll-in-place' is true, this command works just like the
  939. command `scroll-down-in-place', scrolling the current window and leaving point
  940. \"in place\" within the window.  See the documentation for the command
  941. `scroll-down-in-place' for more information.
  942.  
  943. When the variable `scroll-in-place' is `nil' this command invokes the standard
  944. GNU Emacs version of `scroll-down'.  In that case, when LINES is `nil' the
  945. current window is scrolled by nearly a complete windowful of text.
  946.  
  947. Note that this command correctly handles cases in which `scroll-in-place' has a
  948. buffer-local value in the window to be scrolled.  That value is honored."
  949.   (interactive "P")
  950.   (scroll-window (scroll-choose-window) lines -1))
  951.  
  952. ;;;
  953. ;;;
  954. ;;;
  955.  
  956. (defun scroll-up (&optional lines)
  957.   "Scroll the text of the current window upward by LINES lines.  As a special
  958. case, when the current window is a minibuffer window, this command scrolls the
  959. `minibuffer-scroll-window' (which is usually the list of completions) if it
  960. exists, or otherwise the next window in the canonical ordering of windows.
  961.  
  962. The argument LINES is optional.  Its meaning depends on the current value of
  963. the variable `scroll-in-place'.
  964.  
  965. When the variable `scroll-in-place' is true, this command works just like the
  966. command `scroll-up-in-place', scrolling the current window and leaving point
  967. \"in place\" within the window.  See the documentation for the command
  968. `scroll-up-in-place' for more information.
  969.  
  970. When the variable `scroll-in-place' is `nil' this command invokes the standard
  971. GNU Emacs version of `scroll-up'.  In that case, when LINES is `nil' the
  972. current window is scrolled by nearly a complete windowful of text.
  973.  
  974. Note that this command correctly handles cases in which `scroll-in-place' has a
  975. buffer-local value in the window to be scrolled.  That value is honored."
  976.   (interactive "P")
  977.   (scroll-window (scroll-choose-window) lines 1))
  978.  
  979. ;;;
  980. ;;; NOTE that in the FSF GNU Emacs 19.26 version of `scroll-other-window-down',
  981. ;;; the `lines' argument is required.  I've left it optional in order to be
  982. ;;; like `scroll-other-window'.
  983. ;;;
  984.  
  985. (defun scroll-other-window-down (&optional lines)
  986.   "Scroll the text of the next window downward by LINES lines.  The next window
  987. is generally the one below the current one, or the one at the top of the screen
  988. if the current window is at the bottom of the screen.  In special circumstances
  989. this command will scroll a window other than the next window.  Read the
  990. documentation for the function `scroll-choose-other-window' for details.
  991.  
  992. The argument LINES is optional.  Its meaning depends on the current value of
  993. the variable `scroll-in-place'.
  994.  
  995. When the variable `scroll-in-place' is true, this command works just like the
  996. command `scroll-other-window-down-in-place', scrolling the next window and
  997. leaving point \"in place\" within that window.  See the documentation for the
  998. command `scroll-other-window-down-in-place' for more information.
  999.  
  1000. When the variable `scroll-in-place' is `nil' this command invokes the standard
  1001. GNU Emacs version of `scroll-other-window-down'.  In that case, when LINES is
  1002. `nil' the next window is scrolled by nearly a complete windowful of text.
  1003. \(Note that `scroll-other-window-down' first appeared as a standard command in
  1004. the FSF's GNU Emacs 19.26.  If the builtin version of that command is not
  1005. available in the current Emacs system, an equivalent action is invoked
  1006. instead.)
  1007.  
  1008. Note that this command correctly handles cases in which `scroll-in-place' has a
  1009. buffer-local value in the window to be scrolled.  That value is honored."
  1010.   (interactive "P")
  1011.   ;; This code is similar to the body of `scroll-window', below.
  1012.   (let* ((other-window (scroll-choose-other-window))
  1013.      (other-window-buffer (window-buffer other-window)))
  1014.     (if ;; Allow `scroll-in-place' to be a buffer-local variable.
  1015.     (save-excursion (set-buffer other-window-buffer) scroll-in-place)
  1016.     (scroll-window-in-place other-window lines -1)
  1017.       
  1018.       ;; Paranoid, we forcibly break any running sequence of "in place"
  1019.       ;; scrolling commands.
  1020.       (setq scroll-previous-window nil)
  1021.       ;; For XEmacs and Lucid GNU Emacs, preserve the region's state.
  1022.       (if (boundp 'zmacs-region-stays)
  1023.       (setq zmacs-region-stays t))
  1024.       (if (fboundp 'original-scroll-other-window-down)
  1025.       (original-scroll-other-window-down lines)
  1026.     ;; `scroll-other-window-down' first appeared as a builtin in FSF GNU
  1027.     ;; Emacs 19.26, so it may not be available in the current Emacs system.
  1028.     ;; Do the equivalent thing.
  1029.     (original-scroll-other-window (cond
  1030.                        ((null lines) '-)
  1031.                        ((eq lines '-) nil)
  1032.                        (t (- (prefix-numeric-value lines)))
  1033.                        ))
  1034.     ))
  1035.     ))
  1036.  
  1037. ;;;
  1038. ;;;
  1039. ;;;
  1040.  
  1041. (defun scroll-other-window (&optional lines)
  1042.   "Scroll the text of the next window upward by LINES lines.  The next window
  1043. is generally the one below the current one, or the one at the top of the screen
  1044. if the current window is at the bottom of the screen.  In special circumstances
  1045. this command will scroll a window other than the next window.  Read the
  1046. documentation for the function `scroll-choose-other-window' for details.
  1047.  
  1048. The argument LINES is optional.  Its meaning depends on the current value of
  1049. the variable `scroll-in-place'.
  1050.  
  1051. When the variable `scroll-in-place' is true, this command works just like the
  1052. command `scroll-other-window-in-place', scrolling the next window and leaving
  1053. point \"in place\" within that window.  See the documentation for the command
  1054. `scroll-other-window-in-place' for more information.
  1055.  
  1056. When the variable `scroll-in-place' is `nil' this command invokes the standard
  1057. GNU Emacs version of `scroll-other-window'.  In that case, when LINES is `nil'
  1058. the next window is scrolled by nearly a complete windowful of text.
  1059.  
  1060. Note that this command correctly handles cases in which `scroll-in-place' has a
  1061. buffer-local value in the window to be scrolled.  That value is honored."
  1062.   (interactive "P")
  1063.   ;; This code is similar to the body of `scroll-window', below.
  1064.   (let* ((other-window (scroll-choose-other-window))
  1065.      (other-window-buffer (window-buffer other-window)))
  1066.     (if ;; Allow `scroll-in-place' to be a buffer-local variable.
  1067.     (save-excursion (set-buffer other-window-buffer) scroll-in-place)
  1068.     (scroll-window-in-place other-window lines 1)
  1069.       
  1070.       ;; Paranoid, we forcibly break any running sequence of "in place"
  1071.       ;; scrolling commands.
  1072.       (setq scroll-previous-window nil)
  1073.       ;; For XEmacs and Lucid GNU Emacs, preserve the region's state.
  1074.       (if (boundp 'zmacs-region-stays)
  1075.       (setq zmacs-region-stays t))
  1076.       (original-scroll-other-window lines))
  1077.     ))
  1078.  
  1079.  
  1080. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1081. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1082. ;;;;
  1083. ;;;; Here are the new functions `scroll-window-in-place', `scroll-window', and
  1084. ;;;; `scroll-window-in-place-continue-sequence'.  These functions are intended
  1085. ;;;; to be available to programs outside this package.
  1086. ;;;;
  1087. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1088. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1089.  
  1090. (defun scroll-window-in-place (window lines direction)
  1091.   "Scroll WINDOW vertically by the given number of window LINES in the given
  1092. DIRECTION, leaving the window's point as close as possible to its original
  1093. window position (window line and column).  In other words, the window's point
  1094. is left \"in place\" within the window.
  1095.  
  1096. Note that the window to be scrolled does not have to be the selected window,
  1097. and that this function does not change which window is selected.
  1098.  
  1099. LINES specifies the number of window lines to scroll and is interpreted as if
  1100. it were a raw prefix argument.  If LINES is `nil', the window is scrolled by
  1101. the amount it was moved by the immediately previous \"in place\" scrolling
  1102. command, or by the value of the variable `scroll-default-lines' (by default,
  1103. almost a windowful) if the previous command was not an \"in place\" scrolling
  1104. command (or when WINDOW is not the previously scrolled window, or when the
  1105. value of `this-command' is not in the same group as the previous scrolling
  1106. command (see the documentation for the variable `scroll-command-groups'), or
  1107. when other circumstances prevent the previous scrolling distance from being
  1108. used).  If LINES is the symbol `-', then the scrolling distance is determined
  1109. as if LINES had been `nil' and then that distance is multiplied by -1.
  1110.  
  1111. DIRECTION determines the direction of the scrolling motion.  The values -1 and
  1112. `down' indicate downward motion; the values 1 and `up' indicate upward motion.
  1113. Any other value causes an error.
  1114.  
  1115. If the window cannot be scrolled by the full distance (because the window hits
  1116. the boundary of its buffer), the window's point is allowed to stray from its
  1117. initial position so that it can move the full number of lines.  If point cannot
  1118. move the full number of lines, point is moved to the buffer boundary (unless it
  1119. was already there, in which case a buffer boundary error is signalled instead).
  1120. Any immediately subsequent \"in place\" scrolling commands will try to restore
  1121. point to its initial window position.
  1122.  
  1123. Unless the variable `scroll-allow-blank-lines-past-eob' is true, this function
  1124. avoids displaying blank lines past the end of the buffer except as necessary to
  1125. make a previous \"in place\" scrolling action reversible.  Effectively, this
  1126. means that this function will not display any more past-end-of-buffer blank
  1127. lines than were visible when the current sequence of \"in place\" scrolling
  1128. commands started.  When the variable `scroll-allow-blank-lines-past-eob' is
  1129. true, this function will display as many blank lines as is necessary to keep
  1130. point \"in place\" in the window.
  1131.  
  1132. Note that if WINDOW is not the selected window and it is impossible to scroll
  1133. the text of WINDOW at all (because a buffer boundary is already visible), then
  1134. this function signals a buffer boundary error.  The error is signalled even if
  1135. point could otherwise move the full number of lines."
  1136.   (let* (;; Make sure that the user doesn't quit in the middle and leave us
  1137.      ;; with our variables out of sync.
  1138.      (inhibit-quit t)
  1139.      (original-window (selected-window))
  1140.      (original-buffer (current-buffer))
  1141.      (window-height (- (window-height window)
  1142.                (if (window-minibuffer-p window)
  1143.                    0 1)))
  1144.      (this-command-group (scroll-get-command-group this-command))
  1145.      (continue-scroll-p
  1146.       (and ;; We're scrolling the previously scrolled window...
  1147.            (windowp scroll-previous-window)
  1148.            (eq window scroll-previous-window)
  1149.            ;; ...and the last command was an "in place" scrolling command
  1150.            ;; that can be continued by this command.
  1151.            (if (eq last-command t)
  1152.            ;; If the previous command signalled an error, the value of
  1153.            ;; `last-command' is `t'.  Try to see if we signalled the
  1154.            ;; error and if point is where we left it.  (NOTE that FSF
  1155.            ;; GNU Emacs 19.23+ no longer sets `last-command' to `t'
  1156.            ;; when a command signals an error.  This is OK because the
  1157.            ;; else part of this `if' does the appropriate thing.)
  1158.            (and    scroll-boundary-error-point
  1159.             (eq (window-point window) scroll-boundary-error-point)
  1160.             (memq scroll-boundary-error-command this-command-group)
  1161.             )
  1162.          ;; Otherwise...
  1163.          (memq last-command this-command-group))
  1164.            ))
  1165.      (lines-value (prefix-numeric-value lines))
  1166.      )
  1167.     
  1168.     ;; For XEmacs and Lucid GNU Emacs, preserve the region's state.  Note that
  1169.     ;; these Emacsen will forcibly deactivate the region if we signal an error
  1170.     ;; later on.  Is this bad?
  1171.     (if (boundp 'zmacs-region-stays)
  1172.     (setq zmacs-region-stays t))
  1173.     ;; Parse the direction into a unit distance (1 or -1).
  1174.     (setq direction (scroll-parse-direction direction))
  1175.     
  1176.     (setq scroll-previous-window window
  1177.       ;; `(setq scroll-boundary-error-command nil)' is not necessary.
  1178.       scroll-boundary-error-point nil)
  1179.     (unwind-protect
  1180.     (progn
  1181.       ;; `select-window' does an implicit `set-buffer'.
  1182.       (select-window window)
  1183.       
  1184.       (if (or ;; The current command is not a continuation of a running
  1185.           ;; sequence of "in place" scrolling commands...
  1186.           (not continue-scroll-p)
  1187.           ;; ...or we were given an explicit number of lines to scroll,
  1188.           ;; and that number has a different magnitude than the last
  1189.           ;; number of lines we scrolled...
  1190.               (and (or (numberp lines) (consp lines))
  1191.                (/= scroll-previous-lines lines-value)
  1192.                (/= scroll-previous-lines (- lines-value)))
  1193.           ;; ...or the last successful scrolling command moved to a
  1194.           ;; buffer boundary, but the buffer is no longer in the state
  1195.           ;; we left it.  (This can occur if, for example, we signal an
  1196.           ;; end-of-buffer error and something catches it and moves
  1197.           ;; point or renarrows.  VM, for example, does this.)
  1198.           (and scroll-boundary-previous-point
  1199.                (or (not (or (bobp) (eobp)))
  1200.                (< scroll-boundary-previous-point (point-min))
  1201.                (> scroll-boundary-previous-point (point-max))
  1202.                (eq scroll-boundary-previous-point (point)))))
  1203.           
  1204.           ;; We're starting a new sequence of scrolling commands.
  1205.           (setq lines (if (or (numberp lines) (consp lines))
  1206.                   lines-value
  1207.                 ;; The default number of lines...
  1208.                 (* (if (eq lines '-) -1 1)
  1209.                    (if (numberp scroll-default-lines)
  1210.                    scroll-default-lines
  1211.                  (max (- window-height
  1212.                      next-screen-context-lines)
  1213.                       1))))
  1214.             scroll-previous-lines lines
  1215.             scroll-goal-column (scroll-determine-goal-column window)
  1216.             scroll-boundary-previous-point nil
  1217.             ;; `(setq scroll-boundary-previous-lines 0)' is not
  1218.             ;; necessary.
  1219.             scroll-window-debt 0
  1220.             scroll-initially-displayed-lines
  1221.             (if scroll-allow-blank-lines-past-eob
  1222.             0
  1223.               (save-excursion
  1224.             (goto-char (window-start window))
  1225.             (vertical-motion (1- window-height)))))
  1226.         
  1227.         ;; Otherwise we want to scroll by the same number of lines (but
  1228.         ;; possibly in a different direction) that we scrolled in previous
  1229.         ;; invocations of this function.
  1230.         (cond ((null lines)
  1231.            (setq lines scroll-previous-lines))
  1232.           ((eq lines '-)
  1233.            (setq lines (- scroll-previous-lines)
  1234.              scroll-previous-lines lines))
  1235.           (t
  1236.            (setq lines lines-value
  1237.              scroll-previous-lines lines)))
  1238.         )
  1239.       
  1240.       (setq lines (* direction lines))
  1241.       
  1242.       ;; If point is not in the window, center window around point.  We try
  1243.       ;; to account for a bug in `pos-visible-in-window-p' in some versions
  1244.       ;; of Emacs (see `scroll-pos-visible-bug-p', above).
  1245.       (save-excursion
  1246.         (if (pos-visible-in-window-p (let ((point (point)))
  1247.                        (if (and scroll-pos-visible-bug-p
  1248.                             (= point (point-max)))
  1249.                            (max (1- point) (point-min))
  1250.                          point))
  1251.                      window)
  1252.         nil
  1253.           (vertical-motion (/ (- window-height) 2))
  1254.           (set-window-start window (point))))
  1255.       
  1256.       (cond ((and scroll-boundary-previous-point
  1257.               ;; `lines' is the same sign as the direction from point
  1258.               ;; to the `scroll-boundary-previous-point'.
  1259.               (cond ((> lines 0)
  1260.                  (> (- scroll-boundary-previous-point (point)) 0))
  1261.                 ((< lines 0)
  1262.                  (< (- scroll-boundary-previous-point (point)) 0))
  1263.                 (t nil)))
  1264.          ;; We're moving away from the buffer boundary.
  1265.          (goto-char scroll-boundary-previous-point)
  1266.          ;; Always move here (i.e., don't reject cases in which the
  1267.          ;; window doesn't move).
  1268.          (scroll-set-window-start window
  1269.                       (- scroll-boundary-previous-lines))
  1270.          ;; (message "Back, window debt is %s." scroll-window-debt)
  1271.          (setq scroll-boundary-previous-point nil))
  1272.  
  1273.         ((= lines 0)
  1274.          ;; We're going nowhere, so save ourselves some work.
  1275.          ;; (message "Scrolled zero lines.")
  1276.          )
  1277.         
  1278.         (t
  1279.          ;; Perform the scrolling motion.
  1280.          (let ((initial-point (point))
  1281.                (moved nil))
  1282.            ;; First move point and see how far it goes.
  1283.            (setq moved (vertical-motion lines))
  1284.            (if (= moved lines)
  1285.                (progn
  1286.              ;; Point moved the full distance.  Move to the desired
  1287.              ;; column and then try to move the window the full
  1288.              ;; distance, too.
  1289.              (move-to-column (+ (current-column)
  1290.                         scroll-goal-column))
  1291.              (or (scroll-set-window-start window moved
  1292.                               original-window)
  1293.                  (scroll-signal-boundary-error initial-point
  1294.                                lines))
  1295.              ;; (message "Normal, window debt is %s."
  1296.              ;;          scroll-window-debt)
  1297.              )
  1298.              ;; Point couldn't move all the way.  Move to the buffer
  1299.              ;; boundary if we're not already there, or signal a buffer
  1300.              ;; boundary error otherwise.
  1301.              (let ((boundary-point (if (< lines 0)
  1302.                            (point-min)
  1303.                          (point-max)))
  1304.                (boundary-symbol (if (< lines 0)
  1305.                         'beginning-of-buffer
  1306.                           'end-of-buffer)))
  1307.                (if (= initial-point boundary-point)
  1308.                (scroll-signal-boundary-error initial-point lines)
  1309.              ;; Scroll the window by as many lines as point could
  1310.              ;; move.
  1311.              (or (scroll-set-window-start window moved
  1312.                               original-window)
  1313.                  (scroll-signal-boundary-error initial-point
  1314.                                lines))
  1315.              (message "%s" (get boundary-symbol 'error-message))
  1316.              ;; (message "Boundary, window debt is %s."
  1317.              ;;          scroll-window-debt)
  1318.              (setq scroll-boundary-previous-lines moved)
  1319.              (setq scroll-boundary-previous-point initial-point)
  1320.              (goto-char boundary-point))
  1321.                )))
  1322.          )))
  1323.       
  1324.       ;; The unwind forms of the `unwind-protect', above.  Restore the
  1325.       ;; originally selected window and current buffer.
  1326.       (select-window original-window)
  1327.       (set-buffer original-buffer)))
  1328.   
  1329.   ;; The standard GNU Emacs scrolling commands return `nil' so we do, too.
  1330.   nil)
  1331.  
  1332. ;;;
  1333. ;;;
  1334. ;;;
  1335.  
  1336. (defun scroll-window (window lines direction)
  1337.   "Scroll WINDOW vertically by the given number of window LINES in the given
  1338. DIRECTION.  Note that the window to be scrolled does not have to be the
  1339. selected window, and that this function does not change which window is
  1340. selected.
  1341.  
  1342. When the variable `scroll-in-place' is true, this function simply invokes the
  1343. function `scroll-window-in-place' to scroll the window and leave point \"in
  1344. place\" within that window.  See the documentation for `scroll-window-in-place'
  1345. for more information.
  1346.  
  1347. When the variable `scroll-in-place' is `nil' this function invokes the original
  1348. version of the standard GNU Emacs command `scroll-down' or `scroll-up', as
  1349. determined by DIRECTION, to scroll the window.  If DIRECTION is -1 or `down',
  1350. the original `scroll-down' is called; if DIRECTION is 1 or `up', the original
  1351. `scroll-up' is called.  Any other DIRECTION is an error.  LINES is interpreted
  1352. as if it were a raw prefix argument.  If LINES is `nil', the window is scrolled
  1353. by almost a complete windowful.  If LINES is the symbol `-', the window is
  1354. scrolled by almost a complete windowful in the opposite direction.
  1355.  
  1356. Note that this function correctly handles cases in which `scroll-in-place' has
  1357. a buffer-local value in the WINDOW's buffer.  That value is honored."
  1358.   (let ((current-buffer (current-buffer))
  1359.     (selected-window (selected-window))
  1360.     (window-buffer (window-buffer window)))
  1361.     (if ;; Allow `scroll-in-place' to be a buffer-local variable.
  1362.     (if (eq current-buffer window-buffer)
  1363.         scroll-in-place
  1364.       (save-excursion (set-buffer window-buffer) scroll-in-place))
  1365.     (scroll-window-in-place window lines direction)
  1366.       
  1367.       (unwind-protect
  1368.       (progn
  1369.         ;; Paranoid, we forcibly break any running sequence of "in place"
  1370.         ;; scrolling commands.
  1371.         (setq scroll-previous-window nil)
  1372.         ;; For XEmacs and Lucid GNU Emacs, preserve the region's state.
  1373.         (if (boundp 'zmacs-region-stays)
  1374.         (setq zmacs-region-stays t))
  1375.         (select-window window)
  1376.         (if (= (scroll-parse-direction direction) 1)
  1377.         (original-scroll-up lines)
  1378.           (original-scroll-down lines)))
  1379.     (select-window selected-window)
  1380.     (set-buffer current-buffer))
  1381.       )))
  1382.  
  1383. ;;;
  1384. ;;; The following function is sometimes useful.  For example, I call it from
  1385. ;;; functions that are invoked by certain mouse button down events in order to
  1386. ;;; preserve any running chain of "in place" scrolling commands.  This lets me
  1387. ;;; continue the sequence from my mouse button up functions.
  1388. ;;;
  1389. ;;; I haven't yet needed a function to purposely break a running sequence of
  1390. ;;; "in place" scrolling commands.  Such a function would be easy to write,
  1391. ;;; however; just set the variable `scroll-previous-window' to `nil'.
  1392. ;;;
  1393.  
  1394. (defun scroll-window-in-place-continue-sequence ()
  1395.   "If the previous command was a \"scroll in place\" command, set the variable
  1396. `this-command' to the name of that previous command.  This ensures that any
  1397. running sequence of \"in place\" scrolling commands will not be broken by the
  1398. current command.  See the documentation for the commands `scroll-down-in-place'
  1399. and `scroll-up-in-place' for more information about \"in place\" scrolling.
  1400.  
  1401. NOTE that you don't need to call this function if the current command scrolls
  1402. in place!  You only need to call this function when the current command is not
  1403. a \"scroll in place\" command but you still want to preserve any running
  1404. sequence of \"in place\" commands.  Such situations are rare.
  1405.  
  1406. NOTE that this function sets `this-command' in order to trick the \"in place\"
  1407. scrolling commands.  If something else subsequently sets `this-command', any
  1408. running sequence of scrolling commands will probably be broken anyway."
  1409.   (if (if (eq last-command t)
  1410.       ;; If `last-command' is `t', then the previous command signalled an
  1411.       ;; error.  See if the last invocation of `scroll-window-in-place'
  1412.       ;; signalled an error.  (NOTE that FSF GNU Emacs 19.23+ no longer
  1413.       ;; sets `last-command' to `t' when a command signals an error.  This
  1414.       ;; is OK because the else part of this `if' does the appropriate
  1415.       ;; thing.)
  1416.       scroll-boundary-error-point
  1417.     ;; Otherwise, the value of `last-command' must belong to some group of
  1418.     ;; "in place" scrolling commands.
  1419.     (or (memq last-command scroll-default-command-group)
  1420.         (let ((groups scroll-command-groups)
  1421.           (found nil))
  1422.           (while (and groups (not found))
  1423.         (if (memq last-command (car groups))
  1424.             (setq found t)
  1425.           (setq groups (cdr groups)))
  1426.         )
  1427.           found)))
  1428.       (setq this-command last-command)))
  1429.  
  1430.  
  1431. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1432. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1433. ;;;;
  1434. ;;;; Here are the various auxiliary functions called by the function `scroll-
  1435. ;;;; window-in-place'.  None of the functions are intended to be called from
  1436. ;;;; outside this package.
  1437. ;;;;
  1438. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1439. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1440.  
  1441. (defun scroll-get-command-group (command)
  1442.   "Return the group of \"in place\" scrolling commands that contains the given
  1443. COMMAND.  This is the list of commands with which the given command may share
  1444. state and form \"chains.\"
  1445.  
  1446. This function is an auxiliary for the function `scroll-window-in-place'.  Don't
  1447. call this function from other code."
  1448.   ;; This function assumes that the given command is an "in place" scrolling
  1449.   ;; command.
  1450.   (let ((groups scroll-command-groups)
  1451.     (found nil))
  1452.     (while (and groups (not found))
  1453.       (if (memq command (car groups))
  1454.       (setq found t)
  1455.     (setq groups (cdr groups)))
  1456.       )
  1457.     (if groups
  1458.     (car groups)
  1459.       ;; Otherwise return the default command group.  If necessary, add the
  1460.       ;; given command to the default command group.
  1461.       (or (memq command scroll-default-command-group)
  1462.       (setq scroll-default-command-group
  1463.         (cons command scroll-default-command-group)))
  1464.       scroll-default-command-group)
  1465.     ))
  1466.  
  1467. ;;;
  1468. ;;;
  1469. ;;;
  1470.  
  1471. (defun scroll-parse-direction (direction)
  1472.   "Return the signed unit distance for the given DIRECTION.  If DIRECTION is
  1473. unacceptable, signal an error."
  1474.   (cond ((or (eq direction 1) (eq direction -1)) direction)
  1475.     ((eq direction 'up) 1)
  1476.     ((eq direction 'down) -1)
  1477.     (t (signal 'args-out-of-range (list 'direction direction)))
  1478.     ))
  1479.  
  1480. ;;;
  1481. ;;;
  1482. ;;;
  1483.  
  1484. (defun scroll-determine-goal-column (window)
  1485.   "Return the goal column for the \"in place\" vertical scrolling commands.
  1486. This is the horizontal window position at which these commands try to keep
  1487. point.
  1488.  
  1489. This function is an auxiliary for the function `scroll-window-in-place'.  Don't
  1490. call this function from other code."
  1491.   ;; NOTE that `window' must be the selected window!  `scroll-window-in-place'
  1492.   ;; ensures that this is so.
  1493.   (cond ((or truncate-lines
  1494.          (and truncate-partial-width-windows
  1495.           (< (window-width window) (screen-width)))
  1496.          (> (window-hscroll window) 0))
  1497.      ;; Lines in this window are being truncated.
  1498.      (if (and track-eol (eolp))
  1499.          9999
  1500.        (current-column)))
  1501.     ((and track-eol (eolp))
  1502.      ;; In some ways this isn't quite right, as point doesn't track the
  1503.      ;; ends of wrapped lines.  But if it did so, point would be on the
  1504.      ;; wrong window line.  This is the best we can do.
  1505.      (1- (window-width window)))
  1506.     (t (% (current-column) (1- (window-width window))))
  1507.     ))
  1508.  
  1509. ;;;
  1510. ;;;
  1511. ;;;
  1512.  
  1513. (defun scroll-set-window-start (window lines &optional original-window)
  1514.   "Move the `window-start' of the given window, which must be the selected
  1515. window.  If the window was successfully scrolled, update the variable
  1516. `scroll-window-debt' and return `t'.  Otherwise return `nil'.
  1517.  
  1518. This function is an auxiliary for the function `scroll-window-in-place'.  Don't
  1519. call this function from other code."
  1520.   (save-excursion
  1521.     (goto-char (window-start window))
  1522.     ;; Try to move the window start by the specified number of lines.  In
  1523.     ;; addition, try to make up any existing debt in the window start's
  1524.     ;; position and make sure that we don't move too close to the end of the
  1525.     ;; buffer.
  1526.     (let ((moved (+ (vertical-motion (+ lines
  1527.                     scroll-window-debt
  1528.                     scroll-initially-displayed-lines))
  1529.             (vertical-motion (- scroll-initially-displayed-lines)))))
  1530.       ;; If we're not scrolling the `original-window' (i.e., the originally
  1531.       ;; selected window), punt if we didn't move the window start at all.
  1532.       (if (and original-window
  1533.            (not (eq window original-window))
  1534.            (= moved 0))
  1535.       nil
  1536.     ;; Otherwise update the window start and keep track of the debt in our
  1537.     ;; position.  Return `t' to indicate success.
  1538.     (set-window-start window (point))
  1539.     (setq scroll-window-debt (- (+ lines scroll-window-debt) moved))
  1540.     t))
  1541.     ))
  1542.  
  1543. ;;;
  1544. ;;;
  1545. ;;;
  1546.  
  1547. (defun scroll-signal-boundary-error (initial-point lines)
  1548.   "Move point to its initial location and signal an appropriate buffer boundary
  1549. error.
  1550.  
  1551. This function is an auxiliary for the function `scroll-window-in-place'.  Don't
  1552. call this function from other code."
  1553.   (goto-char initial-point)
  1554.   ;; Remember what we were doing and where point was when we signalled the
  1555.   ;; error so that subsequent "in place" scrolling commands can decide how to
  1556.   ;; recover.
  1557.   (setq scroll-boundary-error-command this-command
  1558.     scroll-boundary-error-point initial-point)
  1559.   (when signal-error-on-buffer-boundary
  1560.     (signal (if (< lines 0) 'beginning-of-buffer 'end-of-buffer)
  1561.         nil)))
  1562.  
  1563.  
  1564. ;;; Some convenience redefinitions for modes that don't like scroll-in-place
  1565. (add-hook 'vm-mode-hook 'turn-off-scroll-in-place)
  1566. (add-hook 'vm-select-message-hook 'turn-off-scroll-in-place)
  1567. (add-hook 'vm-summary-mode-hook 'turn-off-scroll-in-place)
  1568.  
  1569. (add-hook 'list-mode-hook 'turn-off-scroll-in-place)
  1570.  
  1571. ;; This doesn't work with Red Gnus
  1572. ;; (add-hook 'gnus-article-mode-hook 'turn-off-scroll-in-place)
  1573.  
  1574. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1575. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1576. ;;;;
  1577. ;;;; Finally, here is the `provide' statement.
  1578. ;;;;
  1579. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1580. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1581.  
  1582. (provide 'scroll-in-place)
  1583.  
  1584. ;;; scroll-in-place.el ends here
  1585.